#include "CDeviceManager.h"
#include "irrlicht.h"
#include "os.h"
namespace game
{
	CDeviceManager::CDeviceManager():
		threadLock(0), 
		VideoThread(0), 
		NetworkThread(0), 
		SoundThread(0),
		EventReceiver(0), 
		VideoDevice(0),
		VideoDriver(0),
		GameSceneManager(0), 
		SceneManager(0),
		GUI(0),
		VideoHandler(0),
		ConfigReader(0)
	{
		irr::os::Printer::log("create CDeviceManager");
		
		irrThread::delegateThreadCallback* callback = new irrThread::delegateThreadCallback;
		*callback += NewDelegate(this, &CDeviceManager::runVideo);


		VideoThread = new irrThread(ETP_ABOVE_LOW, callback, "DeviceManagerInternal", (void*)"");
		VideoThread->start();
	};

	CDeviceManager* CDeviceManager::Instance()
	{
		static CDeviceManager  instance;
		return &instance;
	}


	CDeviceManager::~CDeviceManager()
	{
		if(VideoThread)
			delete VideoThread;

		if(VideoHandler)
			VideoHandler->drop();

		if(GameSceneManager)
			GameSceneManager->drop();
		
		if(EventReceiver)
			delete EventReceiver;
	}
	
	
	//!	VideoDevice and render must be in mutual thread
	void CDeviceManager::runVideo(void*data)
	{
		//Create IrrlichtDevice before anything variables
		this->VideoDevice = irr::createDevice();
		this->VideoDriver = VideoDevice->getVideoDriver();
		this->SceneManager = VideoDevice->getSceneManager();

		this->EventReceiver = createUserActionEventReceiver(this);
		
		//Create VideoHandler before GameSceneManager
		this->VideoHandler = video::createVideoHandler(this);
		
		this->GameSceneManager = scene::createGameSceneManager(this);


		this->ConfigReader = io::createConfigReader(this);

		this->EventReceiver->UAction += NewDelegate(this->GameSceneManager, &scene::IGameSceneManager::onUserAction);

		
		GUI = VideoDevice->getGUIEnvironment();

		if(EventReceiver)
		{
			irr::IEventReceiver* customEventReceiver = this->EventReceiver;
			this->VideoDevice->setEventReceiver(customEventReceiver);
			
			EventReceiver->startEventProcess();
		}

		u32 sceneStartTime = 0;
		u32 currentTime = VideoDevice->getTimer()->getTime();
		u32 sceneSkipTime = 15;

		while (IsVideoDeviceRun = VideoDevice->run())
		{
			IDeviceManager::lockVideo();
			
			video::IVideoHandler::delegateAction* action = this->VideoHandler->popAction();
			
			//run custom actions
			while (action != NULL)
			{
				if(!action->IsNull())
				{
					void* arg = (void*)NULL;

					if((*action).Data != NULL)
					{
						arg = (*action).Data;
					}
					
					(*action)(arg);
				}

				action = this->VideoHandler->popAction();
			};

			currentTime = VideoDevice->getTimer()->getTime();

			DeltaTime = (f32)(currentTime - LastRenderTime) / 1000.0f; //in seconds

			LastRenderTime = currentTime;

			if ((currentTime - sceneStartTime > sceneSkipTime) || (sceneStartTime == 0))
			{

				sceneStartTime = VideoDevice->getTimer()->getTime();

				VideoDriver->beginScene(true, true, irr::video::SColor(255,100,101,140));

				SceneManager->drawAll();
				GUI->drawAll();
				
				VideoDriver->endScene();
			}

			IDeviceManager::unlockVideo();

		}  
	}

	void CDeviceManager::stop()
	{
		IDeviceManager::lockVideo();

		EventReceiver->stopEventProcess();

		if(VideoDevice)
		{
			VideoDevice->closeDevice();
			VideoDevice->drop();
		}

		IDeviceManager::unlockVideo();
	}

	void CDeviceManager::clearScreen()
	{
		IDeviceManager::lockVideo();

		GUI->clear();
		SceneManager->clear();

		IDeviceManager::unlockVideo();
	}
	
	IUserActionEventReceiver* CDeviceManager::getUserEventReceiver()
	{
		return this->EventReceiver;
	}

	irr::gui::IGUIEnvironment* CDeviceManager::getGUIEnvironment()
	{
		return this->GUI;
	};

	irr::scene::ISceneManager* CDeviceManager::getSceneManager()
	{
		return this->SceneManager;
	};

	scene::IGameSceneManager* CDeviceManager::getGameSceneManager()
	{
		return this->GameSceneManager;
	};

	bool CDeviceManager::getIsVideoDeviceRun()
	{
		return this->IsVideoDeviceRun;
	};

	irrThread* CDeviceManager::getVideoThread()
	{
		return this->VideoThread;
	};

	irr::IrrlichtDevice* CDeviceManager::getVideoDevice()
	{
		return this->VideoDevice;
	};

	video::IVideoHandler* CDeviceManager::getVideoHandler()
	{
	   return this->VideoHandler;
	}

	io::IConfigReader* CDeviceManager::getConfigReader()
	{
		return this->ConfigReader;
	}
}
